package org.filecollector.filecontroller.virtualcatalogue;

import lombok.NonNull;
import org.filecollector.filecontroller.virtualcatalogue.groupname.GroupName;
import org.filecollector.filecontroller.virtualcatalogue.groupname.GroupNameFactory;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Factory produces {@link VirtualCatalogue} implementations
 */
public abstract class VirtualCatalogueFactory {
    /**
     * Constructs from directory
     * @param directory tracking directory
     * @param dependencies dependencies
     * @return VirtualCatalogue or empty if any troubles occurred
     */
    public static Optional<VirtualCatalogue> constructFromDirectory(
            File directory, VirtualCatalogueDependencies dependencies
    ) {
        if (!VirtualCatalogueStaticMethods.checkDirectory(directory, dependencies.error(), dependencies.warner())) {
            return Optional.empty();
        }
        GroupName groupName;
        try {
            groupName = GroupNameFactory.getGroupNameByString(directory.getName()).orElseThrow();
        } catch (NoSuchElementException e) {
            dependencies.warner().accept(
                    String.format(
                            "Directory %s wasn't created: name not matches to pattern",
                            directory.getPath()
                    )
            );
            return Optional.empty();
        } catch (RuntimeException e) {
            dependencies.warner().accept(
                    String.format(
                            "Something went wrong with directory %s", directory.getPath()
                    )
            );
            return Optional.empty();
        }
        var dao = new VirtualCatalogueDao(new ConcurrentHashMap<>(), directory, groupName);
        return Optional.of(new VirtualCatalogueClass(dao, dependencies).startingInitialization());
    }

    /**
     * Parse and creates Catalogue from string path
     * @param namePath path to file in String format
     * @param dependencies dependencies of catalogue
     * @return VirtualCatalogue or empty if something went wrong
     */
    public static Optional<VirtualCatalogue> constructFromString(
            @NonNull String namePath,
            @NonNull VirtualCatalogueDependencies dependencies
    ) {
        File directory;
        try {
            directory = new File(namePath);
            if (!GroupNameFactory.isCorrect(directory.getName())) {
                dependencies.warner().accept(
                        String.format(
                                "Directory %s does not have correct name",
                                namePath
                        )
                );
                return Optional.empty();
            }
            if (!directory.exists()) {
                Files.createDirectory(directory.toPath());
                if (!directory.exists()) {
                    dependencies.warner().accept(
                            String.format(
                                    "Directory %s cannot be created for some reasons",
                                    namePath
                            )
                    );
                    return Optional.empty();
                } else {
                    if (!directory.isDirectory()) {
                        dependencies.warner().accept(
                                String.format(
                                        "Directory %s cannot be created: it already exists ant it is NOT a file",
                                        namePath
                                )
                        );
                        return Optional.empty();
                    }
                }
            }
        } catch(UnsupportedOperationException e) {
            dependencies.warner().accept(
                    String.format(
                            "Directory %s cannot be created: Troubles with attributes",
                            namePath
                    )
            );
            return Optional.empty();
        } catch (SecurityException e) {
            dependencies.warner().accept(
                    String.format(
                            "Directory %s cannot be created: program has no permissions for directory",
                            namePath
                    )
            );
            return Optional.empty();
        } catch (IOException | RuntimeException e) {
            dependencies.warner().accept(
                    String.format(
                            "Directory %s cannot be created: Something goes wrong",
                            namePath
                    )
            );
            return Optional.empty();
        }
        if (!(directory.isDirectory() && directory.canRead() && directory.canWrite())) {
            dependencies.warner().accept(
                    String.format(
                            "Undefined troubles with directory %s creation",
                            namePath
                    )
            );
            return Optional.empty();
        }
        var groupName = GroupNameFactory.getGroupNameByString(directory.getName());
        if (groupName.isEmpty()) {
            dependencies.warner().accept(
                    String.format(
                            "Directory %s cannot be created: Name wrong",
                            namePath
                    )
            );
        }
        // Possible warns send to Logger by constructFromDirectoryMethod
        return VirtualCatalogueFactory.constructFromDirectory(
                directory,
                dependencies
        );
    }

    public static VirtualCatalogue constructTest(String dirName) {
        File dir;
        try {
            dir = Files.createTempDirectory("init").toFile();
            dir.deleteOnExit();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        var name = GroupNameFactory.getGroupNameByString(dirName);
        var dao = new VirtualCatalogueDao(
                new ConcurrentHashMap<>(),
                dir,
                name.get()
        );
        var dependencies = VirtualCatalogueDependencies.getTest();
        return new VirtualCatalogueClass(dao, dependencies);
    }
}
